from typing import Union, List, Set, Dict

from fastapi import FastAPI,Body
from pydantic import BaseModel, Field, HttpUrl

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

app = FastAPI()

'''
1.1 使用 Pydantic 模型
'''
@app.post("/items1/")
async def create_item(item: Item):
    return item


'''使用模型'''
@app.post("/items2/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict


'''请求体 + 路径参数 + 查询参数'''
@app.put("/items3/{item_id}")
async def create_item(item_id: int, item: Item, q: Union[str, None] = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result

'''数据模型使用 Field'''
class Item1(BaseModel):
    name: str
    description: Union[str, None] = Field(
        default=None, title="The description of the item", max_length=300
    )
    price: float = Field(
        gt=0, description="The price must be greater than zero"
    )
    tax: Union[float, None] = None

@app.put("/items4/{item_id}")
async def update_item(item_id: int, item: Item1):
    results = {"item_id": item_id, "item": item}
    return results


'''
1.2 使用 Body
'''
'''请求体中的单一值,可以使用 Body 指示 FastAPI 将其作为请求体的另一个键进行处理'''
class User(BaseModel):
    username: str
    full_name: Union[str, None] = None


@app.put("/items5/{item_id}")
async def update_item(item_id: int, user: User, single: int = Body()):
    results = {"item_id": item_id, "user": user, "single": single}
    return results


'''嵌入单个请求体参数'''
@app.put("/items6/{item_id}")
async def update_item(item_id: int, user: User = Body(embed=True)):
    results = {"item_id": item_id, "user": user}
    return results


'''
2.1 List 字段
'''
'''未声明元素类型'''
class Model1(BaseModel):
    name: str
    price: float
    tags: list = []

@app.put("/model1/{model_id}")
async def update_model(model_id: int, model: Model1):
    results = {"model_id": model_id, "model": model}
    return results

'''声明元素类型'''
class Model2(BaseModel):
    name: str
    price: float
    tags: List[str] = [] #声明具有子类型的列表,要声明具有子类型的类型，例如 list、dict、tuple：

@app.put("/model2/{model_id}")
async def update_model(model_id: int, model: Model2):
    results = {"model_id": model_id, "model": model}
    return results

'''
2.2 Set 类型
'''
class Model3(BaseModel):
    name: str
    price: float
    mtags: Set[str] = set()

@app.put("/model3/{model_id}")
async def update_model(model_id: int, model: Model3):
    results = {"model_id": model_id, "model": model}
    return results

'''
2.3 嵌套模型
'''
#定义一个 Image 模型作为子模型
class Image(BaseModel):
    url: str
    name: str

class Base1(BaseModel):
    name: str
    description: Union[str, None] = None
    image: Union[Image, None] = None #将子模型用作类型

@app.put("/base1/{base_id}")
async def update_base(base_id: int, base: Base1):
    results = {"item_id": base_id, "item": base}
    return results

'''
2.3 特殊的类型和校验
'''
'''HttpUrl'''
class Image1(BaseModel):
    url: HttpUrl
    name: str

'''纯列表请求体'''
@app.post("/images/multiple/")
async def create_multiple_images(images: List[Image]):
    return images

'''任意 dict 构成的请求体'''
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
    return weights




if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)